<!DOCTYPE html>
<html>

  <head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <title>安卓自定义View进阶-Matrix详解</title>
  <meta name="description" content="Matrix详解，详细讲解Android中的Matrix原理，了解Matrix各种方法，以及关于Matrix的一些实用技巧，补充了setPolyToPoly的详细信息。">
  <meta name="author" content="GcsSloop">
  <meta name="keywords" content="Matrix, Matrix原理, Matrix详解, mapPoints, mapRadius, mapRect, mapVectors, setPolyToPoly, setRectToRect, rectStaysRect, setSinCos, invert, isAffine, isIdentity, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  <meta name="关键字" content="Matrix, Matrix原理, Matrix详解, mapPoints, mapRadius, mapRect, mapVectors, setPolyToPoly, setRectToRect, rectStaysRect, setSinCos, invert, isAffine, isIdentity, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  

  <meta name="twitter:card" content="summary">
  <meta name="twitter:title" content="安卓自定义View进阶-Matrix详解">
  <meta name="twitter:description" content="Matrix详解，详细讲解Android中的Matrix原理，了解Matrix各种方法，以及关于Matrix的一些实用技巧，补充了setPolyToPoly的详细信息。">
  <meta name="twitter:keywords" content="Matrix, Matrix原理, Matrix详解, mapPoints, mapRadius, mapRect, mapVectors, setPolyToPoly, setRectToRect, rectStaysRect, setSinCos, invert, isAffine, isIdentity, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  
  <meta property="og:type" content="article">
  <meta property="og:title" content="安卓自定义View进阶-Matrix详解">
  <meta property="og:description" content="Matrix详解，详细讲解Android中的Matrix原理，了解Matrix各种方法，以及关于Matrix的一些实用技巧，补充了setPolyToPoly的详细信息。">
  <meta name="og:keywords" content="Matrix, Matrix原理, Matrix详解, mapPoints, mapRadius, mapRect, mapVectors, setPolyToPoly, setRectToRect, rectStaysRect, setSinCos, invert, isAffine, isIdentity, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">

  <meta name="theme-color" content="#343434">
  
  <link rel="icon" type="image/png" href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" />
  <link href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" rel="shortcut icon" type="image/png">
  
  <link href="//netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/css/main.css">

  <link rel="canonical" href="http://www.gcssloop.com/customview/Matrix_Method">
  <link rel="alternate" type="application/rss+xml" title="GcsSloop" href="http://www.gcssloop.com/feed.xml">
  
  <meta name="google-site-verification" content="Z_g58PkzRAyBMxkqrcDdWrTBK8oOWM-7rUHauhLNF2E" />
  <meta name="baidu-site-verification" content="kUtTXCKaZs" />
  <meta name="baidu-site-verification" content="6DuDv3aaJX" />
  
  <!--阅读次数统计-->
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"> </script>
  
  <!--Fuck Weixin and Baidu-->
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv=”Cache-Control” content=”no-siteapp” />
  <meta name="applicable-device" content="pc,mobile">
  <meta name="HandheldFriendly" content="true"/>

  <!-- Google Ad -->
  <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
  <script>
    (adsbygoogle = window.adsbygoogle || []).push({
      google_ad_client: "ca-pub-2767831356529421",
      enable_page_level_ads: true
    });
  </script>

</head>


  <body>

    <span class="mobile btn-mobile-menu">
        <i class="fa fa-list btn-mobile-menu__icon"></i>
        <i class="fa fa-angle-up btn-mobile-close__icon hidden"></i>
    </span>
    
    <header class="panel-cover panel-cover--collapsed" style="background-image: url('/assets/siteinfo/background-cover.jpg')">
  <div class="panel-main">

    <div class="panel-main__inner panel-inverted">
    <div class="panel-main__content">

        <a href="/#blog" title="前往 GcsSloop 的主页" class="blog-button"><img src="/assets/siteinfo/avatar.jpg" width="80" alt="GcsSloop logo" class="panel-cover__logo logo" /></a>
        <h1 class="panel-cover__title panel-title"><a href="/#blog" title="link to homepage for GcsSloop" class="blog-button">GcsSloop</a></h1>

        
        <span class="panel-cover__subtitle panel-subtitle">Just do IT later.</span>
        
        <hr class="panel-cover__divider" />
        <p class="panel-cover__description">嗨，我是 GcsSloop，一名来自2.5次元的魔法师，Android自定义View系列文章作者，非著名程序员。</p>
        <hr class="panel-cover__divider panel-cover__divider--secondary" />
        
        
        <p class="panel-cover__description">欢迎来到我的魔法世界!</p>
        
        
        <div class="navigation-wrapper">
          <div>
            <nav class="cover-navigation cover-navigation--primary">
              <ul class="navigation">
                <li class="navigation__item"><a href="/#blog" title="访问博客" class="blog-button">博客</a></li>
                
                  
                    <li class="navigation__item"><a href="https://github.com/GcsSloop" target="_blank" title="GcsSloop's GitHub">GitHub</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/timeline" title="博客目录">目录</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="https://xiaozhuanlan.com/u/GcsSloop" target="_blank" title="小专栏">专栏</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/category/customview" title="自定义View教程目录">自定义控件</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/friends" title="友链">友链</a></li>
                  
                  
                
              </ul>
            </nav>
          </div>
          
          <div><nav class="cover-navigation navigation--social">
  <ul class="navigation">

  
  <!-- Weibo -->
  <li class="navigation__item">
    <a href="http://weibo.com/GcsSloop" title="@GcsSloop 的微博" target="_blank">
      <i class='social fa fa-weibo'></i>
      <span class="label">Weibo</span>
    </a>
  </li>
  

  
  <!-- Github -->
  <li class="navigation__item">
    <a href="https://github.com/GcsSloop" title="@GcsSloop 的 Github" target="_blank">
      <i class='social fa fa-github'></i>
      <span class="label">Github</span>
    </a>
  </li>
  
  
  
  <!-- Twitter -->
  <li class="navigation__item">
    <a href="http://twitter.com/GcsSloop" title="@GcsSloop" target="_blank">
      <i class='social fa fa-twitter'></i>
      <span class="label">Twitter</span>
    </a>
  </li>
  

    

  

  
  <!-- RSS -->
  <li class="navigation__item">
    <a href="/feed.xml" rel="author" title="RSS" target="_blank">
      <i class='social fa fa-rss'></i>
      <span class="label">RSS</span>
    </a>
  </li>
  

  
  <!-- Email -->
  <li class="navigation__item">
    <a href="mailto:GcsSloop@gmail.com" title="发邮件给我">
      <i class='social fa fa-envelope'></i>
      <span class="label">Email</span>
    </a>
  </li>
  

  
  <!-- Copyright -->
  <li class="navigation__item">
    <a href="http://choosealicense.online" title="选择版权"  target="_blank">
      <i class="social fa fa-copyright"></i>
      <span class="label">版权</span>
    </a>
  </li>
  
  
  </ul>
</nav>
</div>
        </div>
      </div>
    </div>
    
    
    <div class="panel-cover--overlay cover-slate"></div>
    
  </div>
</header>


    <div class="content-wrapper">
        <div class="content-wrapper__inner">
            <article class="post-container post-container--single" itemscope itemtype="http://schema.org/BlogPosting">
  <header class="post-header">
    <div class="post-meta" style="font-size:.8em">
      <time datetime="2016-08-30 00:00:00 +0800" itemprop="datePublished" class="post-meta__date date">2016-08-30</time> &#8226; <span class="post-meta__tags tags">自定义View,Matrix</span> &#8226; View <span id="busuanzi_value_page_pv"></span> times.
</span>
    </div>
    <h1 class="post-title">安卓自定义View进阶-Matrix详解</h1>
  </header>

  <section class="post">
    <p>这应该是目前最详细的一篇讲解Matrix的中文文章了，在上一篇文章<a href="http://www.gcssloop.com/customview/Matrix_Basic">Matrix原理</a>中，我们对Matrix做了一个简单的了解，偏向理论，在本文中则会详细的讲解Matrix的具体用法，以及与Matrix相关的一些实用技巧。</p>

<blockquote>
  <h2 id="️-警告测试本文章示例之前请关闭硬件加速">⚠️ 警告：测试本文章示例之前请关闭硬件加速。</h2>
</blockquote>

<h2 id="matrix方法表">Matrix方法表</h2>

<p>按照惯例，先放方法表做概览。</p>

<table>
  <thead>
    <tr>
      <th>方法类别</th>
      <th>相关API</th>
      <th>摘要</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>基本方法</td>
      <td>equals hashCode toString toShortString</td>
      <td>比较、 获取哈希值、 转换为字符串</td>
    </tr>
    <tr>
      <td>数值操作</td>
      <td>set reset setValues getValues</td>
      <td>设置、 重置、 设置数值、 获取数值</td>
    </tr>
    <tr>
      <td>数值计算</td>
      <td>mapPoints mapRadius mapRect mapVectors</td>
      <td>计算变换后的数值</td>
    </tr>
    <tr>
      <td>设置(set)</td>
      <td>setConcat setRotate setScale setSkew setTranslate</td>
      <td>设置变换</td>
    </tr>
    <tr>
      <td>前乘(pre)</td>
      <td>preConcat preRotate preScale preSkew preTranslate</td>
      <td>前乘变换</td>
    </tr>
    <tr>
      <td>后乘(post)</td>
      <td>postConcat postRotate postScale postSkew postTranslate</td>
      <td>后乘变换</td>
    </tr>
    <tr>
      <td>特殊方法</td>
      <td>setPolyToPoly setRectToRect rectStaysRect setSinCos</td>
      <td>一些特殊操作</td>
    </tr>
    <tr>
      <td>矩阵相关</td>
      <td>invert isAffine(API21) isIdentity</td>
      <td>求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 …</td>
    </tr>
  </tbody>
</table>

<h2 id="matrix方法详解">Matrix方法详解</h2>

<h3 id="构造方法">构造方法</h3>

<p>构造方法没有在上面表格中列出。</p>

<h4 id="无参构造">无参构造</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="o">()</span>
</code></pre>
</div>
<p>创建一个全新的Matrix，使用格式如下：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
</code></pre>
</div>

<p>通过这种方式创建出来的并不是一个数值全部为空的矩阵，而是一个单位矩阵,如下:</p>

<p><img src="http://latex.codecogs.com/png.latex?$$
\left [ 
\begin{matrix} 
1 &amp; 0 &amp; 0 \\\
0 &amp; 1 &amp; 0 \\\
0 &amp; 0 &amp; 1 
\end{1} 
\right ]
$$" alt="" /></p>

<h4 id="有参构造">有参构造</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="o">(</span><span class="n">Matrix</span> <span class="n">src</span><span class="o">)</span>
</code></pre>
</div>

<p>这种方法则需要一个已经存在的矩阵作为参数，使用格式如下:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">(</span><span class="n">src</span><span class="o">);</span>
</code></pre>
</div>

<p>创建一个Matrix，并对src深拷贝(理解为新的matrix和src是两个对象，但内部数值相同即可)。</p>

<h3 id="基本方法">基本方法</h3>

<p>基本方法内容比较简单，在此处简要介绍一下。</p>

<h4 id="1equals">1.equals</h4>

<p>比较两个Matrix的数值是否相同。</p>

<h4 id="2hashcode">2.hashCode</h4>

<p>获取Matrix的哈希值。</p>

<h4 id="3tostring">3.toString</h4>

<p>将Matrix转换为字符串: <code class="highlighter-rouge">Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}</code></p>

<h4 id="4toshortstring">4.toShortString</h4>

<p>将Matrix转换为短字符串: <code class="highlighter-rouge">[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]</code></p>

<h3 id="数值操作">数值操作</h3>

<p>数值操作这一组方法可以帮助我们直接控制Matrix里面的数值。</p>

<h4 id="1set">1.set</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">set</span> <span class="o">(</span><span class="n">Matrix</span> <span class="n">src</span><span class="o">)</span>
</code></pre>
</div>

<p>没有返回值，有一个参数，作用是将参数Matrix的数值复制到当前Matrix中。如果参数为空，则重置当前Matrix，相当于<code class="highlighter-rouge">reset()</code>。</p>

<h4 id="2reset">2.reset</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">reset</span> <span class="o">()</span>
</code></pre>
</div>

<p>重置当前Matrix(将当前Matrix重置为单位矩阵)。</p>

<h4 id="3setvalues">3.setValues</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">setValues</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">values</span><span class="o">)</span>
</code></pre>
</div>

<p>setValues的参数是浮点型的一维数组，长度需要大于9，拷贝数组中的前9位数值赋值给当前Matrix。</p>

<h4 id="4getvalues">4.getValues</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">getValues</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">values</span><span class="o">)</span>
</code></pre>
</div>

<p>很显然，getValues和setValues是一对方法，参数也是浮点型的一维数组，长度需要大于9，将Matrix中的数值拷贝进参数的前9位中。</p>

<h3 id="数值计算">数值计算</h3>

<h4 id="1mappoints">1.mapPoints</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">mapPoints</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">pts</span><span class="o">)</span>

<span class="kt">void</span> <span class="nf">mapPoints</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span><span class="o">,</span> <span class="kt">float</span><span class="o">[]</span> <span class="n">src</span><span class="o">)</span>

<span class="kt">void</span> <span class="nf">mapPoints</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span><span class="o">,</span> <span class="kt">int</span> <span class="n">dstIndex</span><span class="o">,</span><span class="kt">float</span><span class="o">[]</span> <span class="n">src</span><span class="o">,</span> <span class="kt">int</span> <span class="n">srcIndex</span><span class="o">,</span> <span class="kt">int</span> <span class="n">pointCount</span><span class="o">)</span>
</code></pre>
</div>

<p>计算一组点基于当前Matrix变换后的位置，(由于是计算点，所以参数中的float数组长度一般都是偶数的,若为奇数，则最后一个数值不参与计算)。</p>

<p>它有三个重载方法:</p>

<p>(1) <code class="highlighter-rouge">void mapPoints (float[] pts)</code> 方法仅有一个参数，pts数组作为参数传递原始数值，计算结果仍存放在pts中。</p>

<p>示例:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">// 初始数据为三个点 (0, 0) (80, 100) (400, 300) </span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">pts</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[]{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">80</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="mi">300</span><span class="o">};</span>

<span class="c1">// 构造一个matrix，x坐标缩放0.5</span>
<span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="n">f</span><span class="o">);</span>

<span class="c1">// 输出pts计算之前数据</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"before: "</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">pts</span><span class="o">));</span>

<span class="c1">// 调用map方法计算</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">mapPoints</span><span class="o">(</span><span class="n">pts</span><span class="o">);</span>

<span class="c1">// 输出pts计算之后数据</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after : "</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">pts</span><span class="o">));</span>
</code></pre>
</div>

<p>结果:</p>

<div class="highlighter-rouge"><pre class="highlight"><code>before: [0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : [0.0, 0.0, 40.0, 100.0, 200.0, 300.0]
</code></pre>
</div>

<p>(2) <code class="highlighter-rouge">void mapPoints (float[] dst, float[] src)</code> ，src作为参数传递原始数值，计算结果存放在dst中，src不变。</p>

<p>如果原始数据需要保留则一般使用这种方法。</p>

<p>示例:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">// 初始数据为三个点 (0, 0) (80, 100) (400, 300)</span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">src</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[]{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">80</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="mi">300</span><span class="o">};</span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[</span><span class="mi">6</span><span class="o">];</span>

<span class="c1">// 构造一个matrix，x坐标缩放0.5</span>
<span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="n">f</span><span class="o">);</span>

<span class="c1">// 输出计算之前数据</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"before: src="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">src</span><span class="o">));</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"before: dst="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">dst</span><span class="o">));</span>

<span class="c1">// 调用map方法计算</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">mapPoints</span><span class="o">(</span><span class="n">dst</span><span class="o">,</span><span class="n">src</span><span class="o">);</span>

<span class="c1">// 输出计算之后数据</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after : src="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">src</span><span class="o">));</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after : dst="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">dst</span><span class="o">));</span>
</code></pre>
</div>

<p>结果:</p>

<div class="highlighter-rouge"><pre class="highlight"><code>before: src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
before: dst=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
after : src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : dst=[0.0, 0.0, 40.0, 100.0, 200.0, 300.0]
</code></pre>
</div>

<p>(3) <code class="highlighter-rouge">void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount)</code> 可以指定只计算一部分数值。</p>

<table>
  <thead>
    <tr>
      <th>参数</th>
      <th>摘要</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>dst</td>
      <td>目标数据</td>
    </tr>
    <tr>
      <td>dstIndex</td>
      <td>目标数据存储位置起始下标</td>
    </tr>
    <tr>
      <td>src</td>
      <td>源数据</td>
    </tr>
    <tr>
      <td>srcIndex</td>
      <td>源数据存储位置起始下标</td>
    </tr>
    <tr>
      <td>pointCount</td>
      <td>计算的点个数</td>
    </tr>
  </tbody>
</table>

<p>示例:</p>

<blockquote>

  <p>将第二、三个点计算后存储进dst最开始位置。</p>
</blockquote>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">// 初始数据为三个点 (0, 0) (80, 100) (400, 300)</span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">src</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[]{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">80</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="mi">300</span><span class="o">};</span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[</span><span class="mi">6</span><span class="o">];</span>

<span class="c1">// 构造一个matrix，x坐标缩放0.5</span>
<span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="n">f</span><span class="o">);</span>

<span class="c1">// 输出计算之前数据</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"before: src="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">src</span><span class="o">));</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"before: dst="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">dst</span><span class="o">));</span>

<span class="c1">// 调用map方法计算(最后一个2表示两个点，即四个数值,并非两个数值)</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">mapPoints</span><span class="o">(</span><span class="n">dst</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">src</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">2</span><span class="o">);</span>

<span class="c1">// 输出计算之后数据</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after : src="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">src</span><span class="o">));</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after : dst="</span><span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">dst</span><span class="o">));</span>
</code></pre>
</div>

<p>结果:</p>

<div class="highlighter-rouge"><pre class="highlight"><code>before: src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
before: dst=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
after : src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : dst=[40.0, 100.0, 200.0, 300.0, 0.0, 0.0]
</code></pre>
</div>

<h4 id="2mapradius">2.mapRadius</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">float</span> <span class="nf">mapRadius</span> <span class="o">(</span><span class="kt">float</span> <span class="n">radius</span><span class="o">)</span>
</code></pre>
</div>

<p>测量半径，由于圆可能会因为画布变换变成椭圆，所以此处测量的是平均半径。</p>

<p>示例:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">float</span> <span class="n">radius</span> <span class="o">=</span> <span class="mi">100</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>

<span class="c1">// 构造一个matrix，x坐标缩放0.5</span>
<span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="n">f</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"mapRadius: "</span><span class="o">+</span><span class="n">radius</span><span class="o">);</span>

<span class="n">result</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">mapRadius</span><span class="o">(</span><span class="n">radius</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"mapRadius: "</span><span class="o">+</span><span class="n">result</span><span class="o">);</span>
</code></pre>
</div>

<p>结果:</p>

<div class="highlighter-rouge"><pre class="highlight"><code>mapRadius: 100.0
mapRadius: 70.71068
</code></pre>
</div>

<h4 id="3maprect">3.mapRect</h4>

<div class="highlighter-rouge"><pre class="highlight"><code>boolean mapRect (RectF rect)

boolean mapRect (RectF dst, RectF src)
</code></pre>
</div>

<p>测量矩形变换后位置。</p>

<p>(1) <code class="highlighter-rouge">boolean mapRect (RectF rect)</code> 测量rect并将测量结果放入rect中，返回值是判断矩形经过变换后是否仍为矩形。</p>

<p>示例：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">RectF</span> <span class="n">rect</span> <span class="o">=</span> <span class="k">new</span> <span class="n">RectF</span><span class="o">(</span><span class="mi">400</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="mi">1000</span><span class="o">,</span> <span class="mi">800</span><span class="o">);</span>

<span class="c1">// 构造一个matrix</span>
<span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="n">f</span><span class="o">);</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">postSkew</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span><span class="mi">0</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"mapRadius: "</span><span class="o">+</span><span class="n">rect</span><span class="o">.</span><span class="na">toString</span><span class="o">());</span>

<span class="kt">boolean</span> <span class="n">result</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">mapRect</span><span class="o">(</span><span class="n">rect</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"mapRadius: "</span><span class="o">+</span><span class="n">rect</span><span class="o">.</span><span class="na">toString</span><span class="o">());</span>
<span class="n">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"isRect: "</span><span class="o">+</span> <span class="n">result</span><span class="o">);</span>
</code></pre>
</div>

<p>结果：</p>

<div class="highlighter-rouge"><pre class="highlight"><code>mapRadius: RectF(400.0, 400.0, 1000.0, 800.0)
mapRadius: RectF(600.0, 400.0, 1300.0, 800.0)
isRect: false
</code></pre>
</div>

<blockquote>

  <p>由于使用了错切，所以返回结果为false。</p>
</blockquote>

<p>(2) <code class="highlighter-rouge">boolean mapRect (RectF dst, RectF src)</code> 测量src并将测量结果放入dst中，返回值是判断矩形经过变换后是否仍为矩形,和之前没有什么太大区别，此处就不啰嗦了。</p>

<h4 id="4mapvectors">4.mapVectors</h4>

<p>测量向量。</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">mapVectors</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">vecs</span><span class="o">)</span>

<span class="kt">void</span> <span class="nf">mapVectors</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span><span class="o">,</span> <span class="kt">float</span><span class="o">[]</span> <span class="n">src</span><span class="o">)</span>

<span class="kt">void</span> <span class="nf">mapVectors</span> <span class="o">(</span><span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span><span class="o">,</span> <span class="kt">int</span> <span class="n">dstIndex</span><span class="o">,</span> <span class="kt">float</span><span class="o">[]</span> <span class="n">src</span><span class="o">,</span> <span class="kt">int</span> <span class="n">srcIndex</span><span class="o">,</span> <span class="kt">int</span> <span class="n">vectorCount</span><span class="o">)</span>
</code></pre>
</div>

<p><code class="highlighter-rouge">mapVectors</code> 与 <code class="highlighter-rouge">mapPoints</code> 基本上是相同的，可以直接参照上面的<code class="highlighter-rouge">mapPoints</code>使用方法。</p>

<p>而两者唯一的区别就是<code class="highlighter-rouge">mapVectors</code>不会受到位移的影响，这符合向量的定律，如果你不了解的话，请找到以前教过你的老师然后把学费要回来。</p>

<p>区别:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">float</span><span class="o">[]</span> <span class="n">src</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[]{</span><span class="mi">1000</span><span class="o">,</span> <span class="mi">800</span><span class="o">};</span>
<span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[</span><span class="mi">2</span><span class="o">];</span>

<span class="c1">// 构造一个matrix</span>
<span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="n">f</span><span class="o">);</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">postTranslate</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span><span class="mi">100</span><span class="o">);</span>

<span class="c1">// 计算向量, 不受位移影响</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">mapVectors</span><span class="o">(</span><span class="n">dst</span><span class="o">,</span> <span class="n">src</span><span class="o">);</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"mapVectors: "</span><span class="o">+</span><span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">dst</span><span class="o">));</span>

<span class="c1">// 计算点</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">mapPoints</span><span class="o">(</span><span class="n">dst</span><span class="o">,</span> <span class="n">src</span><span class="o">);</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"mapPoints: "</span><span class="o">+</span><span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">dst</span><span class="o">));</span>
</code></pre>
</div>

<p>结果:</p>

<div class="highlighter-rouge"><pre class="highlight"><code>mapVectors: [500.0, 800.0]
mapPoints: [600.0, 900.0]
</code></pre>
</div>

<h3 id="setpre-与-post">set、pre 与 post</h3>

<p>对于四种基本变换 平移(translate)、缩放(scale)、旋转(rotate)、 错切(skew) 它们每一种都三种操作方法，分别为 设置(set)、 前乘(pre) 和 后乘 (post)。而它们的基础是Concat，通过先构造出特殊矩阵然后用原始矩阵Concat特殊矩阵，达到变换的结果。</p>

<p><strong>关于四种基本变换的知识和三种对应操作的区别，详细可以参考 <a href="http://www.gcssloop.com/customview/Canvas_Convert/">Canvas之画布操作</a> 和 <a href="http://www.gcssloop.com/customview/Matrix_Basic/">Matrix原理</a> 这两篇文章的内容。</strong></p>

<p>由于之前的文章已经详细的讲解过了它们的原理与用法，所以此处就简要的介绍一下:</p>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>set</td>
      <td>设置，会覆盖掉之前的数值，导致之前的操作失效。</td>
    </tr>
    <tr>
      <td>pre</td>
      <td>前乘，相当于矩阵的右乘， <code class="highlighter-rouge">M' = M * S</code>  (S指为特殊矩阵)</td>
    </tr>
    <tr>
      <td>post</td>
      <td>后乘，相当于矩阵的左乘，<code class="highlighter-rouge">M' = S * M</code> （S指为特殊矩阵）</td>
    </tr>
  </tbody>
</table>

<p><strong>Matrix 相关的重要知识：</strong></p>

<ul>
  <li>
    <p>1.一开始从Canvas中获取到到Matrix并不是初始矩阵，而是经过偏移后到矩阵，且偏移距离就是距离屏幕左上角的位置。</p>
  </li>
  <li>
    <blockquote>
      <p>这个可以用于判定View在屏幕上的绝对位置，View可以根据所处位置做出调整。</p>
    </blockquote>
  </li>
  <li>
    <p>2.构造Matrix时使用的是矩阵乘法，前乘(pre)与后乘(post)结果差别很大。</p>
  </li>
  <li>
    <blockquote>
      <p>这个直接参见上一篇文章 <a href="http://www.gcssloop.com/customview/Matrix_Basic/">Matrix原理</a> 即可。</p>
    </blockquote>
  </li>
  <li>
    <p>3.受矩阵乘法影响，后面的执行的操作可能会影响到之前的操作。</p>
  </li>
  <li>
    <blockquote>
      <p>使用时需要注意构造顺序。</p>
    </blockquote>
  </li>
</ul>

<h3 id="特殊方法">特殊方法</h3>

<p>这一类方法看似不起眼，但拿来稍微加工一下就可能制作意想不到的效果。</p>

<h4 id="1setpolytopoly">1.setPolyToPoly</h4>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">boolean</span> <span class="nf">setPolyToPoly</span> <span class="o">(</span>
        <span class="kt">float</span><span class="o">[]</span> <span class="n">src</span><span class="o">,</span>    <span class="c1">// 原始数组 src [x,y]，存储内容为一组点</span>
        <span class="kt">int</span> <span class="n">srcIndex</span><span class="o">,</span>   <span class="c1">// 原始数组开始位置</span>
        <span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span><span class="o">,</span>    <span class="c1">// 目标数组 dst [x,y]，存储内容为一组点</span>
        <span class="kt">int</span> <span class="n">dstIndex</span><span class="o">,</span>   <span class="c1">// 目标数组开始位置</span>
        <span class="kt">int</span> <span class="n">pointCount</span><span class="o">)</span> <span class="c1">// 测控点的数量 取值范围是: 0到4</span>
</code></pre>
</div>

<p>Poly全称是Polygon，多边形的意思，了解了意思大致就能知道这个方法是做什么用的了，应该与PS中自由变换中的扭曲有点类似。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071522.gif?gcssloop" alt="" /></p>

<blockquote>
  <p>从参数我们可以了解到setPolyToPoly最多可以支持4个点，这四个点通常为图形的四个角，可以通过这四个角将视图从矩形变换成其他形状。</p>
</blockquote>

<p>简单示例:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MatrixSetPolyToPolyTest</span> <span class="kd">extends</span> <span class="n">View</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="n">Bitmap</span> <span class="n">mBitmap</span><span class="o">;</span>             <span class="c1">// 要绘制的图片</span>
    <span class="kd">private</span> <span class="n">Matrix</span> <span class="n">mPolyMatrix</span><span class="o">;</span>         <span class="c1">// 测试setPolyToPoly用的Matrix</span>

    <span class="kd">public</span> <span class="nf">MatrixSetPolyToPolyTest</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>

        <span class="n">initBitmapAndMatrix</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">initBitmapAndMatrix</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">mBitmap</span> <span class="o">=</span> <span class="n">BitmapFactory</span><span class="o">.</span><span class="na">decodeResource</span><span class="o">(</span><span class="n">getResources</span><span class="o">(),</span>
                <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">poly_test</span><span class="o">);</span>

        <span class="n">mPolyMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>


        <span class="kt">float</span><span class="o">[]</span> <span class="n">src</span> <span class="o">=</span> <span class="o">{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span>                                    <span class="c1">// 左上</span>
                <span class="n">mBitmap</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="mi">0</span><span class="o">,</span>                          <span class="c1">// 右上</span>
                <span class="n">mBitmap</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">mBitmap</span><span class="o">.</span><span class="na">getHeight</span><span class="o">(),</span>        <span class="c1">// 右下</span>
                <span class="mi">0</span><span class="o">,</span> <span class="n">mBitmap</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()};</span>                        <span class="c1">// 左下</span>

        <span class="kt">float</span><span class="o">[]</span> <span class="n">dst</span> <span class="o">=</span> <span class="o">{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span>                                    <span class="c1">// 左上</span>
                <span class="n">mBitmap</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="mi">400</span><span class="o">,</span>                        <span class="c1">// 右上</span>
                <span class="n">mBitmap</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">mBitmap</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">-</span> <span class="mi">200</span><span class="o">,</span>  <span class="c1">// 右下</span>
                <span class="mi">0</span><span class="o">,</span> <span class="n">mBitmap</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()};</span>                        <span class="c1">// 左下</span>

        <span class="c1">// 核心要点</span>
        <span class="n">mPolyMatrix</span><span class="o">.</span><span class="na">setPolyToPoly</span><span class="o">(</span><span class="n">src</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">dst</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">src</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="o">);</span> <span class="c1">// src.length &gt;&gt; 1 为位移运算 相当于处以2</span>

        <span class="c1">// 此处为了更好的显示对图片进行了等比缩放和平移(图片本身有点大)</span>
        <span class="n">mPolyMatrix</span><span class="o">.</span><span class="na">postScale</span><span class="o">(</span><span class="mf">0.26f</span><span class="o">,</span> <span class="mf">0.26f</span><span class="o">);</span>
        <span class="n">mPolyMatrix</span><span class="o">.</span><span class="na">postTranslate</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span><span class="mi">200</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onDraw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onDraw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>

        <span class="c1">// 根据Matrix绘制一个变换后的图片</span>
        <span class="n">canvas</span><span class="o">.</span><span class="na">drawBitmap</span><span class="o">(</span><span class="n">mBitmap</span><span class="o">,</span> <span class="n">mPolyMatrix</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071523.jpg?gcssloop" alt="" /></p>

<p>文章发出后有小伙伴在GitHub上提出疑问，说此处讲解到并不清楚，尤其是最后的一个参数，所以特此补充一下内容。</p>

<p>我们知道<code class="highlighter-rouge">pointCount</code>支持点的个数为0到4个，四个一般指图形的四个角，属于最常用的一种情形，但前面几种是什么情况呢？</p>

<blockquote>
  <p>发布此文的时候之所以没有讲解0到3的情况，是因为前面的几种情况在实际开发中很少会出现，   <del>才不是因为偷懒呢，哼。</del></p>
</blockquote>

<table>
  <thead>
    <tr>
      <th style="text-align: center">pointCount</th>
      <th>摘要</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">0</td>
      <td>相当于<code class="highlighter-rouge">reset</code></td>
    </tr>
    <tr>
      <td style="text-align: center">1</td>
      <td>相当于<code class="highlighter-rouge">translate</code></td>
    </tr>
    <tr>
      <td style="text-align: center">2</td>
      <td>可以进行 缩放、旋转、平移 变换</td>
    </tr>
    <tr>
      <td style="text-align: center">3</td>
      <td>可以进行 缩放、旋转、平移、错切 变换</td>
    </tr>
    <tr>
      <td style="text-align: center">4</td>
      <td>可以进行 缩放、旋转、平移、错切以及任何形变</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>从上表我们可以观察出一个规律, 随着<code class="highlighter-rouge">pointCount</code>数值增大setPolyToPoly的可以操作性也越来越强，这不是废话么，可调整点数多了能干的事情自然也多了。</p>

  <p>只列一个表格就算交代完毕了显得诚意不足，为了彰显诚意，接下来详细的讲解一下。</p>
</blockquote>

<p><strong>为什么说前面几种情况在实际开发中很少出现?</strong></p>

<p>作为开发人员，写出来的代码出了要让机器”看懂”，没有歧义之外，最重要的还是让人看懂，以方便后期的维护修改，从上边的表格中可以看出，前面的几种种情况都可以有更直观的替代方法，只有四个参数的情况下的特殊形变是没有替代方法的。</p>

<p><strong>测控点选取位置?</strong></p>

<p>测控点可以选择任何你认为方便的位置，只要src与dst一一对应即可。不过为了方便，通常会选择一些特殊的点： 图形的四个角，边线的中心点以及图形的中心点等。<strong>不过有一点需要注意，测控点选取都应当是不重复的(src与dst均是如此)，如果选取了重复的点会直接导致测量失效，这也意味着，你不允许将一个方形(四个点)映射为三角形(四个点，但其中两个位置重叠)，但可以接近于三角形。</strong>。</p>

<p><strong>作用范围?</strong></p>

<p>作用范围当然是设置了Matrix的全部区域，如果你将这个Matrix赋值给了Canvas，它的作用范围就是整个画布，如果你赋值给了Bitmap，它的作用范围就是整张图片。</p>

<hr />

<p><strong>接下来用示例演示一下，所有示例的src均为图片大小，dst根据手势变化。</strong></p>

<p><strong>pointCount为0</strong></p>

<p>pointCount为0和<code class="highlighter-rouge">reset</code>是等价的，而不是保持matrix不变，在最底层的实现中可以看到这样的代码：</p>

<div class="language-c++ highlighter-rouge"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">count</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="o">-&gt;</span><span class="n">reset</span><span class="p">();</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071524.gif?gcssloop" alt="" /></p>

<p><strong>pointCount为1</strong></p>

<p>pointCount为0和<code class="highlighter-rouge">translate</code>是等价的，在最底层的实现中可以看到这样的代码：</p>

<div class="language-c++ highlighter-rouge"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="mi">1</span> <span class="o">==</span> <span class="n">count</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="o">-&gt;</span><span class="n">setTranslate</span><span class="p">(</span><span class="n">dst</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fX</span> <span class="o">-</span> <span class="n">src</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fX</span><span class="p">,</span> <span class="n">dst</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fY</span> <span class="o">-</span> <span class="n">src</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fY</span><span class="p">);</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>

<blockquote>
  <p>平移的距离是dst - src.</p>
</blockquote>

<p>当测控点为1的时候，由于你只有一个点可以控制，所以你只能拖拽着它在2D平面上滑动。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071527.gif?gcssloop" alt="" /></p>

<p><strong>pointCount为2</strong></p>

<p>当pointCount为2的时候，可以做缩放、平移和旋转。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071531.gif?gcssloop" alt="" /></p>

<p><strong>pointCount为3</strong></p>

<p>当pointCount为3的时候，可以做缩放、平移、旋转和错切。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071533.gif?gcssloop" alt="" /></p>

<p><strong>pointCount为4</strong></p>

<p>当pointCount为4的时候，你可以将图像拉伸为任意四边形。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071534.gif?gcssloop" alt="" /></p>

<p>上面已经用图例比较详细的展示了不同操控点个数的情况，如果你依旧存在疑问，可以获取代码自己试一下。</p>

<h4><a href="https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/Code/SetPolyToPoly.md" target="_blank">点击此处查看setPolyToPoly测试代码</a></h4>

<h4 id="2setrecttorect">2.setRectToRect</h4>

<pre><code class="language-JAVA">boolean setRectToRect (RectF src,           // 源区域
                RectF dst,                  // 目标区域
                Matrix.ScaleToFit stf)      // 缩放适配模式
</code></pre>

<p>简单来说就是将源矩形的内容填充到目标矩形中，然而在大多数的情况下，源矩形和目标矩形的长宽比是不一致的，到底该如何填充呢，这个填充的模式就由第三个参数 <code class="highlighter-rouge">stf</code> 来确定。</p>

<p>ScaleToFit 是一个枚举类型，共包含了四种模式:</p>

<table>
  <thead>
    <tr>
      <th>模式</th>
      <th>摘要</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>CENTER</td>
      <td>居中，对src等比例缩放，将其居中放置在dst中。</td>
    </tr>
    <tr>
      <td>START</td>
      <td>顶部，对src等比例缩放，将其放置在dst的左上角。</td>
    </tr>
    <tr>
      <td>END</td>
      <td>底部，对src等比例缩放，将其放置在dst的右下角。</td>
    </tr>
    <tr>
      <td>FILL</td>
      <td>充满，拉伸src的宽和高，使其完全填充满dst。</td>
    </tr>
  </tbody>
</table>

<p>下面我们看一下不同宽高比的src与dst在不同模式下是怎样的。</p>

<blockquote>
  <p>假设灰色部分是dst，橙色部分是src，由于是测试不同宽高比，示例中让dst保持不变，看两种宽高比的src在不同模式下填充的位置。</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th style="text-align: center">src(原始状态)</th>
      <th style="text-align: center"><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071535.jpg?gcssloop" alt="" /></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">CENTER</td>
      <td style="text-align: center"><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071538.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td style="text-align: center">START</td>
      <td style="text-align: center"><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071545.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td style="text-align: center">END</td>
      <td style="text-align: center"><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071548.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td style="text-align: center">FILL</td>
      <td style="text-align: center"><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071549.jpg?gcssloop" alt="" /></td>
    </tr>
  </tbody>
</table>

<p>下面用代码演示一下居中的示例:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MatrixSetRectToRectTest</span> <span class="kd">extends</span> <span class="n">View</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">TAG</span> <span class="o">=</span> <span class="s">"MatrixSetRectToRectTest"</span><span class="o">;</span>

    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mViewWidth</span><span class="o">,</span> <span class="n">mViewHeight</span><span class="o">;</span>

    <span class="kd">private</span> <span class="n">Bitmap</span> <span class="n">mBitmap</span><span class="o">;</span>             <span class="c1">// 要绘制的图片</span>
    <span class="kd">private</span> <span class="n">Matrix</span> <span class="n">mRectMatrix</span><span class="o">;</span>         <span class="c1">// 测试etRectToRect用的Matrix</span>

    <span class="kd">public</span> <span class="nf">MatrixSetRectToRectTest</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>

        <span class="n">mBitmap</span> <span class="o">=</span> <span class="n">BitmapFactory</span><span class="o">.</span><span class="na">decodeResource</span><span class="o">(</span><span class="n">getResources</span><span class="o">(),</span> <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">rect_test</span><span class="o">);</span>
        <span class="n">mRectMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onSizeChanged</span><span class="o">(</span><span class="kt">int</span> <span class="n">w</span><span class="o">,</span> <span class="kt">int</span> <span class="n">h</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldw</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldh</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onSizeChanged</span><span class="o">(</span><span class="n">w</span><span class="o">,</span> <span class="n">h</span><span class="o">,</span> <span class="n">oldw</span><span class="o">,</span> <span class="n">oldh</span><span class="o">);</span>
        <span class="n">mViewWidth</span> <span class="o">=</span> <span class="n">w</span><span class="o">;</span>
        <span class="n">mViewHeight</span> <span class="o">=</span> <span class="n">h</span><span class="o">;</span>

    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onDraw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onDraw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>

        <span class="n">RectF</span> <span class="n">src</span><span class="o">=</span> <span class="k">new</span> <span class="n">RectF</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">mBitmap</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">mBitmap</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">);</span>
        <span class="n">RectF</span> <span class="n">dst</span> <span class="o">=</span> <span class="k">new</span> <span class="n">RectF</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">mViewWidth</span><span class="o">,</span> <span class="n">mViewHeight</span> <span class="o">);</span>

        <span class="c1">// 核心要点</span>
        <span class="n">mRectMatrix</span><span class="o">.</span><span class="na">setRectToRect</span><span class="o">(</span><span class="n">src</span><span class="o">,</span><span class="n">dst</span><span class="o">,</span> <span class="n">Matrix</span><span class="o">.</span><span class="na">ScaleToFit</span><span class="o">.</span><span class="na">CENTER</span><span class="o">);</span>

        <span class="c1">// 根据Matrix绘制一个变换后的图片</span>
        <span class="n">canvas</span><span class="o">.</span><span class="na">drawBitmap</span><span class="o">(</span><span class="n">mBitmap</span><span class="o">,</span> <span class="n">mRectMatrix</span><span class="o">,</span> <span class="k">new</span> <span class="n">Paint</span><span class="o">());</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071551.jpg?gcssloop" alt="" /></p>

<h4 id="3rectstaysrect">3.rectStaysRect</h4>

<p>判断矩形经过变换后是否仍为矩形，假如Matrix进行了平移、缩放则画布仅仅是位置和大小改变，矩形变换后仍然为矩形，但Matrix进行了非90度倍数的旋转或者错切，则矩形变换后就不再是矩形了，这个很好理解，不过多赘述，顺便说一下，前面的<code class="highlighter-rouge">mapRect</code>方法的返回值就是根据<code class="highlighter-rouge">rectStaysRect</code>来判断的。</p>

<h4 id="4setsincos">4.setSinCos</h4>

<p>设置sinCos值，这个是控制Matrix旋转的，由于Matrix已经封装好了Rotate方法，所以这个并不常用，在此仅作概述。</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">// 方法一</span>
<span class="kt">void</span> <span class="nf">setSinCos</span> <span class="o">(</span><span class="kt">float</span> <span class="n">sinValue</span><span class="o">,</span>     <span class="c1">// 旋转角度的sin值</span>
                <span class="kt">float</span> <span class="n">cosValue</span><span class="o">)</span>     <span class="c1">// 旋转角度的cos值</span>

<span class="c1">// 方法二</span>
<span class="kt">void</span> <span class="nf">setSinCos</span> <span class="o">(</span><span class="kt">float</span> <span class="n">sinValue</span><span class="o">,</span>     <span class="c1">// 旋转角度的sin值</span>
                <span class="kt">float</span> <span class="n">cosValue</span><span class="o">,</span>     <span class="c1">// 旋转角度的cos值</span>
                <span class="kt">float</span> <span class="n">px</span><span class="o">,</span>           <span class="c1">// 中心位置x坐标</span>
                <span class="kt">float</span> <span class="n">py</span><span class="o">)</span>           <span class="c1">// 中心位置y坐标</span>
</code></pre>
</div>

<p>简单测试:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="c1">// 旋转90度</span>
<span class="c1">// sin90=1</span>
<span class="c1">// cos90=0</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setSinCos</span><span class="o">(</span><span class="mi">1</span><span class="n">f</span><span class="o">,</span> <span class="mi">0</span><span class="n">f</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"setSinCos:"</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">toShortString</span><span class="o">());</span>

<span class="c1">// 重置</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">reset</span><span class="o">();</span>

<span class="c1">// 旋转90度</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setRotate</span><span class="o">(</span><span class="mi">90</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"setRotate:"</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">toShortString</span><span class="o">());</span>
</code></pre>
</div>

<p>结果:</p>

<div class="language-shell highlighter-rouge"><pre class="highlight"><code>setSinCos:[0.0, -1.0, 0.0][1.0, 0.0, 0.0][0.0, 0.0, 1.0]
setRotate:[0.0, -1.0, 0.0][1.0, 0.0, 0.0][0.0, 0.0, 1.0]
</code></pre>
</div>

<h3 id="矩阵相关">矩阵相关</h3>

<p>矩阵相关的函数就属于哪一种非常靠近底层的东西了，大部分开发者很少直接接触这些东西，想要弄明白这个可以回去请教你们的线性代数老师，这里也仅作概述。</p>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>摘要</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>invert</td>
      <td>求矩阵的逆矩阵</td>
    </tr>
    <tr>
      <td>isAffine</td>
      <td>判断当前矩阵是否为仿射矩阵，API21(5.0)才添加的方法。</td>
    </tr>
    <tr>
      <td>isIdentity</td>
      <td>判断当前矩阵是否为单位矩阵。</td>
    </tr>
  </tbody>
</table>

<h4 id="1invert">1.invert</h4>

<p>求矩阵的逆矩阵，简而言之就是计算与之前相反的矩阵，如果之前是平移200px，则求的矩阵为反向平移200px，如果之前是缩小到0.5f，则结果是放大到2倍。</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">boolean</span> <span class="nf">invert</span> <span class="o">(</span><span class="n">Matrix</span> <span class="n">inverse</span><span class="o">)</span>
</code></pre>
</div>

<p>简单测试:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">Matrix</span> <span class="n">invert</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">setTranslate</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span><span class="mi">500</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"before - matrix "</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">toShortString</span><span class="o">()</span> <span class="o">);</span>

<span class="n">Boolean</span> <span class="n">result</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">invert</span><span class="o">(</span><span class="n">invert</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after  - result "</span><span class="o">+</span><span class="n">result</span> <span class="o">);</span>
<span class="n">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after  - matrix "</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">toShortString</span><span class="o">()</span> <span class="o">);</span>
<span class="n">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"after  - invert "</span><span class="o">+</span><span class="n">invert</span><span class="o">.</span><span class="na">toShortString</span><span class="o">()</span> <span class="o">);</span>
</code></pre>
</div>

<p>结果：</p>

<div class="language-shell highlighter-rouge"><pre class="highlight"><code>before - matrix <span class="o">[</span>1.0, 0.0, 200.0][0.0, 1.0, 500.0][0.0, 0.0, 1.0]
after  - result <span class="nb">true
</span>after  - matrix <span class="o">[</span>1.0, 0.0, 200.0][0.0, 1.0, 500.0][0.0, 0.0, 1.0]
after  - invert <span class="o">[</span>1.0, 0.0, -200.0][0.0, 1.0, -500.0][0.0, 0.0, 1.0]
</code></pre>
</div>

<h4 id="2isaffine">2.isAffine</h4>

<p>判断矩阵是否是仿射矩阵, 貌似并没有太大卵用，因为你无论如何操作结果始终都为true。</p>

<p>这是为什么呢？因为迄今为止我们使用的所有变换都是仿射变换，那变换出来的矩阵自然是仿射矩阵喽。</p>

<p>判断是否是仿射矩阵最重要的一点就是，直线是否仍为直线，简单想一下就知道，不论平移，旋转，错切，缩放，直线变换后最终仍为直线，要想让<code class="highlighter-rouge">isAffine</code>的结果变为false，除非你能把直线掰弯，我目前还没有找到能够掰弯的方法，所以我仍是直男(就算找到了，我依旧是直男)。</p>

<p>简单测试:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span><span class="s">"isAffine="</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">isAffine</span><span class="o">());</span>

<span class="n">matrix</span><span class="o">.</span><span class="na">postTranslate</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span><span class="mi">0</span><span class="o">);</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">postScale</span><span class="o">(</span><span class="mf">0.5f</span><span class="o">,</span> <span class="mi">1</span><span class="o">);</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">postSkew</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span><span class="mi">1</span><span class="o">);</span>
<span class="n">matrix</span><span class="o">.</span><span class="na">postRotate</span><span class="o">(</span><span class="mi">56</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span><span class="s">"isAffine="</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">isAffine</span><span class="o">());</span>
</code></pre>
</div>

<p>结果:</p>

<div class="language-shell highlighter-rouge"><pre class="highlight"><code><span class="nv">isAffine</span><span class="o">=</span><span class="nb">true
</span><span class="nv">isAffine</span><span class="o">=</span><span class="nb">true</span>
</code></pre>
</div>

<h4 id="3isidentity">3.isIdentity</h4>

<p>判断是否为单位矩阵，什么是单位矩阵呢，就是文章一开始的那个:</p>

<p><img src="http://latex.codecogs.com/png.latex?$$
\left [ 
\begin{matrix} 
1 &amp; 0 &amp; 0 \\\
0 &amp; 1 &amp; 0 \\\
0 &amp; 0 &amp; 1 
\end{1} 
\right ]
$$" alt="" /></p>

<p>新创建的Matrix和重置后的Matrix都是单位矩阵，不过，只要随意操作一步，就不在是单位矩阵了。</p>

<p>简单测试：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span><span class="s">"isIdentity="</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">isIdentity</span><span class="o">());</span>

<span class="n">matrix</span><span class="o">.</span><span class="na">postTranslate</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span><span class="mi">0</span><span class="o">);</span>

<span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span><span class="s">"isIdentity="</span><span class="o">+</span><span class="n">matrix</span><span class="o">.</span><span class="na">isIdentity</span><span class="o">());</span>
</code></pre>
</div>

<p>结果：</p>

<div class="language-shell highlighter-rouge"><pre class="highlight"><code><span class="nv">isIdentity</span><span class="o">=</span><span class="nb">true
</span><span class="nv">isIdentity</span><span class="o">=</span><span class="nb">false</span>
</code></pre>
</div>

<h2 id="matrix实用技巧">Matrix实用技巧</h2>

<p>通过前面的代码和示例，我们已经了解了Matrix大部分方法是如何使用的，这些基本的原理和方法通过组合可能会创造出神奇的东西，网上有很多教程讲Bitmap利用Matrix变换来制作镜像倒影等，这都属于Matrix的基本应用，我就不在赘述了，下面我简要介绍几种然并卵的小技巧，更多的大家可以开启自己的脑洞来发挥。</p>

<h3 id="1获取view在屏幕上的绝对位置">1.获取View在屏幕上的绝对位置</h3>

<p>在之前的文章<a href="http://www.gcssloop.com/customview/Matrix_Basic/">Matrix原理</a>中我们提到过Matrix最根本的作用就是坐标映射，将View的相对坐标映射为屏幕的绝对坐标，也提到过我们在onDraw函数的canvas中获取到到Matrix并不是单位矩阵，结合这两点，聪明的你肯定想到了我们可以从canvas的Matrix入手取得View在屏幕上的绝对位置。</p>

<p>不过，这也仅仅是一个然并卵的小技巧而已，使用<code class="highlighter-rouge">getLocationOnScreen</code>同样可以获取View在屏幕的位置，但如果你是想让下一任接盘侠弄不明白你在做什么或者是被同事打死的话，尽管这么做。</p>

<p>简单示例:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="nd">@Override</span>
<span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onDraw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">float</span><span class="o">[]</span> <span class="n">values</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">float</span><span class="o">[</span><span class="mi">9</span><span class="o">];</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">location1</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="mi">2</span><span class="o">];</span>

    <span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">canvas</span><span class="o">.</span><span class="na">getMatrix</span><span class="o">();</span>
    <span class="n">matrix</span><span class="o">.</span><span class="na">getValues</span><span class="o">(</span><span class="n">values</span><span class="o">);</span>

    <span class="n">location1</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="n">values</span><span class="o">[</span><span class="mi">2</span><span class="o">];</span>
    <span class="n">location1</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="n">values</span><span class="o">[</span><span class="mi">5</span><span class="o">];</span>
    <span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"location1 = "</span> <span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">location1</span><span class="o">));</span>

    <span class="kt">int</span><span class="o">[]</span> <span class="n">location2</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="mi">2</span><span class="o">];</span>
    <span class="k">this</span><span class="o">.</span><span class="na">getLocationOnScreen</span><span class="o">(</span><span class="n">location2</span><span class="o">);</span>
    <span class="n">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">"location2 = "</span> <span class="o">+</span> <span class="n">Arrays</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">location2</span><span class="o">));</span>
<span class="o">}</span>
</code></pre>
</div>

<p>结果:</p>

<div class="language-shell highlighter-rouge"><pre class="highlight"><code>location1 <span class="o">=</span> <span class="o">[</span>0, 243]
location2 <span class="o">=</span> <span class="o">[</span>0, 243]
</code></pre>
</div>

<h3 id="2利用setpolytopoly制造3d效果">2.利用setPolyToPoly制造3D效果</h3>

<p>这个全凭大家想象力啦，不过我搜了一下还真搜到了好东西，之前鸿洋大大发过一篇博文详细讲解了利用setPolyToPoly制造的折叠效果布局，大家直接到他的博客去看吧，我就不写了。</p>

<blockquote>
  <p>图片引用自鸿洋大大的博客，稍作了一下处理。</p>
</blockquote>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071553.gif?gcssloop" alt="" /></p>

<p>博文链接:</p>

<p><strong><a href="http://blog.csdn.net/lmj623565791/article/details/44278417">Android FoldingLayout 折叠布局 原理及实现（一）</a></strong></p>

<p><strong><a href="http://blog.csdn.net/lmj623565791/article/details/44283093">Android FoldingLayout 折叠布局 原理及实现（二）</a></strong></p>

<h2 id="总结">总结</h2>

<p>本篇基本讲解了Matrix相关的所有方法，应该是目前对Matrix讲解最全面的一篇中文文章了，建议配合上一篇<a href="http://www.gcssloop.com/customview/Matrix_Basic">Matrix原理</a>食用效果更佳。</p>

<p>由于本人水平有限，可能出于误解或者笔误难免出错，如果发现有问题或者对文中内容存在疑问欢迎在下面评论区告诉我，请对问题描述尽量详细，以帮助我可以快速找到问题根源。</p>

<h2 id="about">About</h2>

<p><a href="http://www.gcssloop.com/customview/CustomViewIndex">本系列相关文章</a></p>

<p>作者微博: <a href="http://weibo.com/GcsSloop">GcsSloop</a></p>

<h2 id="参考资料">参考资料</h2>

<p><a href="https://developer.android.com/reference/android/graphics/Matrix.html">Matrix</a><br />
<a href="https://developer.android.com/reference/android/graphics/Matrix.ScaleToFit.html">Matrix.ScaleToFit</a><br />
<a href="http://biandroid.iteye.com/blog/1399462">Android中图像变换Matrix的原理、代码验证和应用</a><br />
<a href="http://code.tutsplus.com/tutorials/understanding-affine-transformations-with-matrix-mathematics--active-10884">Understanding Affine Transformations With Matrix Mathematics</a><br /></p>

    <hr>
  </section>
</article>

<!--广告-->

<!--
<div>
<a href="https://m.aliyun.com/act/team1111/?spm=5176.11533457.1089570.5.424777e3AF8WOJ&userCode=hn5smxtw#/" target="_blank"><img src="/assets/aliyun/1111-980-120.jpg" width="100%"></a>
</div>
-->
<!--捐赠晶石-->
<section class="contribute">
    <script type="text/javascript"> 
      function toggle() {
        var con = document.getElementById("contribute");
        if (con.style.display == "none") {
          con.style.display = "block";
        } else {
          con.style.display = "none";
        }
      }
    </script> 
    <blockquote style="background-color:#F5F5F5; padding: 10px 20px 20px 10px; margin:0px" >
      <h4> 如果你觉得我的文章对你有帮助的话，欢迎赞助一些服务器费用! </h4>
      <p></p>
      <a id=“btn-toggle-contribute” class="btn-contribute" onclick="toggle()" >¥ 点击赞助</a>
      <br>
      <div id="contribute" style="display:none;">
        <p align="center" >
        <img src="/assets/images/wechat.png" alt="微信">
        <img src="/assets/images/alipay.png" alt="支付宝">
        </p>
        <p align="left" >
          <b>感谢所有支持我的魔法师，所有支持过我的魔法师都可以通过微信(GcsSloop)联系我，获赠我的付费专栏！</b>
          <!--
          <a href="/contribute">点击这里查看捐赠者名单。</a>
          -->
        </p>
      </div>
    </blockquote>
</section>
<div>
  <h2>欢迎关注我的微信公众号</h2>
  <img src="/assets/images/banner.jpg" width="100%">
</div>

<!--阅读更多-->
<section class="read-more">
  
  
  <div class="read-more-item">
    <span class="read-more-item-dim">最近的文章</span>
    <h2 class="post-list__post-title post-title"><a href="/course/jitpack-sources-javadoc" title="link to 用JitPack发布开源库时附加文档和源码">用JitPack发布开源库时附加文档和源码</a></h2>
    <p class="excerpt">很早之前写过一篇用JitPack发布Android开源库的文章，有小伙伴反馈说发布到JitPack上的开源库没有文档注释，使用起来很不方便，这是我的失误，上一篇文章只是讲解了如何使用JitPac...&hellip;</p>
    <div class="post-list__meta">
      <time datetime="2016-09-09 00:00:00 +0800" class="post-list__meta--date date">2016-09-09</time> &#8226; <span class="post-list__meta--tags tags">Course</span>
      <br/><br/>
      <a style="float:none; margin:0 auto;" class="btn-border-small" href=/course/jitpack-sources-javadoc>继续阅读</a></div>
   </div>
   
   
   
   
   <div class="read-more-item">
       <span class="read-more-item-dim">更早的文章</span>
       <h2 class="post-list__post-title post-title"><a href="/tips/arratlist-linkedlist-performance" title="link to ArrayList与LinkedList遍历性能比较">ArrayList与LinkedList遍历性能比较</a></h2>
       <p class="excerpt">用实例测试ArrayList与LinkedList遍历性能。结构差别:我们常用的List有两种，ArrayList和LinkedList，虽然两者都是LIst，但由于内部存储结构的不同，使用不同...&hellip;</p>
       <div class="post-list__meta">
          <time datetime="2016-08-21 00:00:00 +0800" class="post-list__meta--date date">2016-08-21</time> &#8226; <span class="post-list__meta--tags tags">Tips</span>
          <br/><br/>
          <a style="float:none; margin:0 auto;" class="btn-border-small" href=/tips/arratlist-linkedlist-performance>继续阅读</a>
       </div>
   </div>
   
</section>

<!--网易云跟帖-->
<!--
<div id="cloud-tie-wrapper" class="cloud-tie-wrapper"></div>
<script src="https://img1.cache.netease.com/f2e/tie/yun/sdk/loader.js"></script>
<script>
var cloudTieConfig = {
  url: document.location.href, 
  sourceId: "",
  productKey: "a85dba2840134721a7b69a15b2e0f217",
  target: "cloud-tie-wrapper"
};
var yunManualLoad = true;
Tie.loader("aHR0cHM6Ly9hcGkuZ2VudGllLjE2My5jb20vcGMvbGl2ZXNjcmlwdC5odG1s", true);
</script>
-->

<style type="text/css">
.isso-comment > div.avatar {
    border: 0px;
    box-shadow: none;
    display: block;
    float: left;
    width: 7%;
    margin: 3px 15px 0 0;
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input {
    border-radius: 6px;
    padding: 6px;
    padding-left: 16px;
    padding-right: 16px;
    border: 1px solid #CCC;
    background-color: #D58D44;
    cursor: pointer;
    outline: 0;
    color: #fff;
    size: 10;
    line-height: 1.4em;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input:hover {
    background-color: #272822;
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input:active {
    background-color: #986530;
}
</style>

<section id="isso-thread"></section>

<script data-isso="//47.52.58.34:1234/"
        data-isso-css="true"
        data-isso-lang="zh"
        data-isso-reply-to-self="false"
        data-isso-require-author="false"
        data-isso-require-email="false"
        data-isso-max-comments-top="10"
        data-isso-max-comments-nested="5"
        data-isso-reveal-on-click="5"
        data-isso-avatar="true"
        data-isso-avatar-bg="#f0f0f0"
        data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
        data-isso-vote="true"
        data-vote-levels=""
        src="//47.52.58.34:1234/js/embed.min.js">
        </script>

<!--
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
-->
<!-- OneV's Den -->
<!--
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-3324997515191619"
     data-ad-slot="9170309685"
     data-ad-format="auto"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
-->

            <section class="footer">
    <footer>
    	<span class="footer__copyright">本站点采用<a rel="license" href="https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh" target="_blank">知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议</a></span>
        <span class="footer__copyright">本站由 <a href="http://www.GcsSloop.com">@GcsSloop</a> 创建，采用 <a href="https://github.com/GcsSloop/Gcs-Vno-Jekyll" target="_blank">Gcs-Vno-Jekyll</a> 作为主题。<span id="busuanzi_container_site_pv"> 总访问量 <span id="busuanzi_value_site_pv"></span> 次</span> - &copy; 2019</span>
        <span class="footer__sitemap, footer__copyright"><a href="http://www.gcssloop.com/sitemap.xml" target="_blank">Site Map</a>
        <a href="http://www.gcssloop.com/vip" target="_blank">vip</a></span>
    </footer>
</section>

        </div>
    </div>
    
    <script type="text/javascript" src="//code.jquery.com/jquery-1.11.3.min.js"></script>

<script type="text/javascript" src="/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<script type="text/javascript" src="/js/main.js"></script>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-82493667-1', 'auto');
  ga('send', 'pageview');

</script>

    
  </body>

</html>
